package com.dd.keel.core.database;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

/**
 * 多数据源管理类
 * @author Kevin.XU
 *
 */
public class MutilDatasource {
	
	final static private Logger LOGGER = LoggerFactory.getLogger(MutilDatasource.class);
	
	private Map<String,ComboPooledDataSource> multi_datasource_map = Collections.synchronizedMap( new HashMap<String,ComboPooledDataSource>() );
	
	/***数据源配置***/
	private Map<String,Properties> datasourceConfigs = new HashMap<String,Properties>();
	
	public MutilDatasource(){}
	
	
	public Map<String, Properties> getDatasourceConfigs() {
		return datasourceConfigs;
	}
	
	public void setDatasourceConfigs(Map<String, Properties> datasourceConfigs) {
		this.datasourceConfigs = datasourceConfigs;
	}
	
	/**
	 * 查询指定数据源的配置
	 * @param datasourceName
	 * @return
	 * @throws Exception
	 */
	private Properties retrieveDatasourceConfig(String datasourceName) throws Exception
	{
		Properties props = datasourceConfigs.get(datasourceName);
		if(props==null || props.isEmpty()) throw new Exception("No datasource config of ["+datasourceName+"]!");
		LOGGER.trace("retrieveDatasourceConfig : {}",props);
		return props;
	}
	
	/**
	 * 直接返回一个JDBC连接
	 * @param key
	 * @return
	 */
	public Connection getConnection(String key) throws Exception
	{
		Properties configProps = retrieveDatasourceConfig(key);
		String user = configProps.getProperty("user");
		String password = configProps.getProperty("password");
		String jdbcUrl = configProps.getProperty("jdbcUrl");
		String driverClass = configProps.getProperty("driverClass");
		try {
			Class.forName(driverClass);
			Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
			return conn;
		} catch (ClassNotFoundException e) {
			LOGGER.error(e.getMessage(), e);
			throw e;
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			throw e;
		}
	}
	
	/**
	 * 返回一个数据源
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public synchronized DataSource getDataSource(String key) throws Exception
	{
		ComboPooledDataSource ds = multi_datasource_map.get(key);
		if(ds!=null)
		{
			LOGGER.debug("@@current connection pool : total = {}, used = {}, idle = {}", new Object[]{ds.getNumConnections(), ds.getNumBusyConnections(), ds.getNumIdleConnections()});
			return ds;
		}else{
			LOGGER.info("@@create connection pool : {}", key);
			Properties configProps = retrieveDatasourceConfig(key);
			//init datasource
			String acquireIncrement = configProps.getProperty("acquireIncrement");
			String initialPoolSize = configProps.getProperty("initialPoolSize");
			String minPoolSize = configProps.getProperty("minPoolSize");
			String maxPoolSize = configProps.getProperty("maxPoolSize");
			String mzxStatements = configProps.getProperty("maxStatements");
			String maxStatementsPerConnection = configProps.getProperty("maxStatementsPerConnection");
			String idleConnectionTestPeriod = configProps.getProperty("idleConnectionTestPeriod");
			String user = configProps.getProperty("user");
			String password = configProps.getProperty("password");
			String jdbcUrl = configProps.getProperty("jdbcUrl");
			String driverClass = configProps.getProperty("driverClass");
			String checkoutTimeout = configProps.getProperty("checkoutTimeout");
			String maxAdministrativeTaskTime = configProps.getProperty("maxAdministrativeTaskTime");
			ComboPooledDataSource cpds = new ComboPooledDataSource();
			if(acquireIncrement!=null) cpds.setAcquireIncrement( Integer.parseInt(acquireIncrement) );
			if(initialPoolSize!=null) cpds.setInitialPoolSize( Integer.parseInt(initialPoolSize) );
			if(minPoolSize!=null) cpds.setMinPoolSize( Integer.parseInt(minPoolSize) );
			if(maxPoolSize!=null) cpds.setMaxPoolSize( Integer.parseInt(maxPoolSize) );
			if(mzxStatements!=null) cpds.setMaxStatements(Integer.parseInt(mzxStatements));
			if(maxStatementsPerConnection!=null) cpds.setMaxStatementsPerConnection(  Integer.parseInt(maxStatementsPerConnection) );
			if(idleConnectionTestPeriod!=null) cpds.setIdleConnectionTestPeriod( Integer.parseInt(idleConnectionTestPeriod) );
			if(checkoutTimeout!=null) cpds.setCheckoutTimeout( Integer.parseInt(checkoutTimeout)*1000 );
			if(maxAdministrativeTaskTime!=null) cpds.setMaxAdministrativeTaskTime(Integer.parseInt(maxAdministrativeTaskTime));			
			cpds.setTestConnectionOnCheckin(false);
			cpds.setTestConnectionOnCheckout(false);
			cpds.setUser( user );
			cpds.setPassword( password );
			cpds.setJdbcUrl( jdbcUrl );
			try {
				cpds.setDriverClass( driverClass );
			} catch (PropertyVetoException ex) {
				LOGGER.error(ex.getMessage(), ex);
			}
			multi_datasource_map.put(key, cpds);
			return cpds;
		}
	}
	
	/**
	 * 关闭连接池
	 */
	public void destroy()
	{
		Iterator<String> keyIter = multi_datasource_map.keySet().iterator();
		while(keyIter.hasNext()){
			String key = keyIter.next();
			LOGGER.debug("destroy datasource [{}]", key);
			ComboPooledDataSource cpds = multi_datasource_map.get(key);
			try{
				DataSources.destroy(cpds);
			}catch(Exception ex){
				LOGGER.error(ex.getMessage(), ex);
			}
		}
	}
	
    
}
